package cn.hairui.blog.controller;

import cn.hairui.blog.configure.WebLog;
import cn.hairui.blog.constant.PubConstant;
import cn.hairui.blog.entity.Myinfo;
import cn.hairui.blog.entity.Resetpwdlog;
import cn.hairui.blog.entity.User;
import cn.hairui.blog.entity.VerifyCode;
import cn.hairui.blog.service.*;
import cn.hairui.blog.util.DateUtil;
import cn.hairui.blog.util.IVerifyCodeGen;
import cn.hairui.blog.util.MD5;
import cn.hairui.blog.util.VerifyCodeGenImpl;
import com.alibaba.druid.support.json.JSONUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;

/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author laoganbu
 * @since 2020-04-07
 */
@Controller

public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private MyinfoService myinfoService;
    @Autowired
    private MailService mailService;
    @Autowired
    private ResetpwdlogService resetpwdlogService;
    @Autowired
    private TypeService typeService;
    @Autowired
    private TagService tagService;

    org.slf4j.Logger logger = LoggerFactory.getLogger("MAIL_SERVICE");

    @RequestMapping(value = "/user/login", method = RequestMethod.GET)
    @WebLog(description = "登录页面")
    public String login(HttpServletRequest request, Model model) {
        // 点击登录按钮默认销毁当前登录session
        HttpSession session = request.getSession();
        session.invalidate();
        // 我的信息
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);
        return "login";
    }

    @RequestMapping(value = "/register")
    public String register(Model model) {
        // 我的信息
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);
        return "register";
    }

    @RequestMapping(value = "/changepwd")
    public String changepwd(Model model, int id, HttpServletRequest request) {
        // 我的信息
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);
        User user = (User) request.getSession().getAttribute(PubConstant.GLOBAL_SESSION_NAME);
        if (user == null || user.getId() != id) {
            return "redirect:/error/403";
        } else {
            model.addAttribute("id", user.getId());
            model.addAttribute("account", user.getAccount());
        }

        return "changepwd";
    }

    @RequestMapping(value = "/user/userlogin", method = RequestMethod.POST)
    @WebLog(description = "登录操作")
    @ResponseBody
    public String userLogin(HttpServletRequest request, User user) {
        Map map = new HashMap();
        String vercodeSession = (String) request.getSession().getAttribute("VerifyCode");
        String vercode = request.getParameter("vercode");
        if (vercode == null || vercodeSession == null || !vercode.toUpperCase().equals(vercodeSession.toUpperCase())) {
            request.getSession().removeAttribute("VerifyCode");
            map.put(PubConstant.flag, PubConstant.failed + "_vercode");
            return JSONUtils.toJSONString(map);
        }

        HttpSession session = request.getSession();
        // session.invalidate();//初始化登录销毁session

        String password = MD5.getMD5ofStr(user.getPassword());

        //通过帐号查询用户状态
        User user1 = userService.getByAccount(user.getAccount());
        if (user1 == null) {
            //用户信息不存在
            map.put(PubConstant.flag, PubConstant.exsit);
            return JSONUtils.toJSONString(map);
        } else {
            //通过用户名密码查询用户信息
            User domain = userService.getByAccountAndPassword(user.getAccount(), password);
            if (domain != null && PubConstant.USER_STATUS_0.equals(domain.getStatus())) {
                session.setAttribute(PubConstant.GLOBAL_SESSION_NAME, domain);
                domain.setLastLoginTime(DateUtil.getCurrentTime());
                domain.setErrorCount(0);
                userService.saveOrUpdate(domain);
                map.put(PubConstant.flag, PubConstant.success);
                return JSONUtils.toJSONString(map);
            } else if (domain != null && PubConstant.USER_STATUS_1.equals(domain.getStatus())) {
                map.put(PubConstant.flag, PubConstant.locked);
                return JSONUtils.toJSONString(map);
            } else {
                //如果帐号存在 将错误记录+1 当错误记录到达规定值时锁定帐号
                int errorCount = user1.getErrorCount();
                if (errorCount == PubConstant.MAX_ERROR_ACCOUNT_TIMES) {
                    user1.setStatus(PubConstant.USER_STATUS_1);
                } else if (errorCount < PubConstant.MAX_ERROR_ACCOUNT_TIMES) {
                    user1.setErrorCount(errorCount + 1);
                    if (errorCount + 1 == PubConstant.MAX_ERROR_ACCOUNT_TIMES) {
                        user1.setStatus(PubConstant.USER_STATUS_1);
                    }
                }
                userService.saveOrUpdate(user1);
                map.put(PubConstant.flag, PubConstant.failed);
                return JSONUtils.toJSONString(map);
            }
        }
    }

    @RequestMapping(value = "/user/sendmail", method = RequestMethod.POST)
    @ResponseBody
    @WebLog(description = "发送邮箱验证码")
    public String sendmail(HttpServletRequest request) {
        Map map = new HashMap();

        String vercodeSession = (String) request.getSession().getAttribute("VerifyCode");
        String vercode = request.getParameter("vercode");
        if (vercode == null || vercodeSession == null || !vercode.toUpperCase().equals(vercodeSession.toUpperCase())) {
            map.put(PubConstant.flag, PubConstant.failed + "_vercode");
            return JSONUtils.toJSONString(map);
        }

        String mailaccount = request.getParameter("mailaccount");

        QueryWrapper<User> queryWrapper3 = new QueryWrapper();
        queryWrapper3.eq("email", mailaccount);
        User user3 = (User) userService.getObj(queryWrapper3);
        if (user3 != null) {
            request.getSession().removeAttribute("VerifyCode");
            map.put(PubConstant.flag, PubConstant.failed + "_vercode");
            return JSONUtils.toJSONString(map);
        }

        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        String mailSubject = "验证码 - " + myinfo.getWebname();

        Integer randNum = (int) (Math.random() * (999999) + 1);//产生(0,999999]之间的随机数
        String mailVerifyCode = String.format("%06d", randNum);//进行六位数补全
        request.getSession().setAttribute("mailVerifyCode", mailVerifyCode);//邮箱验证码保存到session中
        request.getSession().setAttribute("mailAddress", mailaccount);
        request.getSession().setAttribute("mailVerifyCodeTime", DateUtil.getCurrentTime());//发送时间保存在session中

        String mailToAddr = mailaccount;
        String mailContent = "您好，您正在" + myinfo.getWebname() + "进行身份验证，本次操作的验证码为：" + mailVerifyCode + "，请在" + PubConstant.MAIL_CODE_EFFECT_MINUTES + "分钟内完成验证。";
        try {
            mailService.sendMail(mailToAddr, mailSubject, mailContent);
        } catch (Exception e) {
            logger.error("发送邮件出现异常，" + e.toString());
            map.put(PubConstant.flag, PubConstant.failed);
            return JSONUtils.toJSONString(map);
        }

        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }

    @RequestMapping(value = "/user/emailverify", method = RequestMethod.POST)
    @ResponseBody
    @WebLog(description = "发送验证信息重置密码")
    public String emailverify(HttpServletRequest request, String email) {
        Map map = new HashMap();

        User user = userService.getByEmail(email);
        if (user == null) {
            map.put(PubConstant.flag, PubConstant.failed + "_no");
            return JSONUtils.toJSONString(map);
        }

        //找回密码发送邮箱链接
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        String mailSubject = "重置密码 - " + myinfo.getWebname();

        String mailToAddr = email;
        String account = user.getAccount();
        //为了便捷 使用两个uuid进行操作
        String token = UUID.randomUUID().toString().replaceAll("-", "") + UUID.randomUUID().toString().replaceAll("-", "");
        Resetpwdlog resetpwdlog = new Resetpwdlog();
        resetpwdlog.setAccount(account);
        resetpwdlog.setToken(token);
        resetpwdlog.setEmail(email);
        resetpwdlog.setSubmitTime(DateUtil.getCurrentTime());

        //String mailContent = "您好，您正在" + myinfo.getWebname() + "进行重置密码操作，请点击链接进行密码重置：http://localhost:8088/resetpwd?account=" + account + "&token=" + token + "，请在" + PubConstant.MAIL_CODE_EFFECT_MINUTES + "分钟内完成验证。如非本人操作，请忽略。";
        String mailContent = "<html>" +
                "<body>" +
                "您好，您正在" + myinfo.getWebname() + "进行重置密码操作，请点击下方链接进行密码重置" +
                "<br/>" +
                "<a href='http://121.199.26.61:8088/user/resetpwd?account=" + account + "&token=" + token + "'>http://121.199.26.61:8088/resetpwd?account=" + account + "&token=" + token + "</a>" +
                "<br/>" +
                "请在" + PubConstant.MAIL_CODE_EFFECT_MINUTES + "分钟内完成验证。如非本人操作，请忽略。" +
                "</body>" +
                "</html>";
        try {
            mailService.sendMail(mailToAddr, mailSubject, mailContent);
            //将信息保存到发送表中
            resetpwdlogService.saveOrUpdate(resetpwdlog);

        } catch (Exception e) {
            logger.error("发送邮件出现异常，" + e.toString());
            map.put(PubConstant.flag, PubConstant.failed);
            return JSONUtils.toJSONString(map);
        }

        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }


    @GetMapping(value = "/user/resetpwd")
    @WebLog(description = "重置密码页面")
    public String resetpwd(HttpServletRequest request, Model model) {
        // 我的信息
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);
        String account = request.getParameter("account");
        String token = request.getParameter("token");

        model.addAttribute("account", account);
        model.addAttribute("token", token);

        Resetpwdlog resetpwdlog = resetpwdlogService.getById(account);
        if (resetpwdlog == null || resetpwdlog.getSubmitTime() == null || resetpwdlog.getToken() == null) {
            return "forget";
        } else {
            if (!resetpwdlog.getToken().equals(token)) {
                return "forget";
            }
        }
        return "resetpwd";
    }


    @RequestMapping(value = "/user/updatepwd")
    @ResponseBody
    @WebLog(description = "修改密码操作")
    public String updatepwd(HttpServletRequest request) {
        Map map = new HashMap();
        String id = request.getParameter("id");
        String account = request.getParameter("account");
        String opassword = request.getParameter("opassword");
        String password = request.getParameter("password");

        User suser = (User) request.getSession().getAttribute(PubConstant.GLOBAL_SESSION_NAME);
        if (suser == null || !id.equals(String.valueOf(suser.getId()))) {
            map.put(PubConstant.flag, PubConstant.failed + "_nologin");
            return JSONUtils.toJSONString(map);
        }

        User user = userService.getByAccount(account);
        if (user != null && id.equals(String.valueOf(user.getId()))) {
            String pwddb = user.getPassword();
            String opasswordMd5 = MD5.getMD5ofStr(opassword);
            if (pwddb.equals(opasswordMd5)) {
                User domain = new User();
                domain.setId(Integer.parseInt(id));
                domain.setPassword(MD5.getMD5ofStr(password));
                userService.saveOrUpdate(domain);

                request.getSession().invalidate();//销毁session

                map.put(PubConstant.flag, PubConstant.success);
                return JSONUtils.toJSONString(map);
            } else {
                map.put(PubConstant.flag, PubConstant.failed + "_pwd");//原来密码错误
                return JSONUtils.toJSONString(map);
            }
        } else {
            map.put(PubConstant.flag, PubConstant.failed);
            return JSONUtils.toJSONString(map);
        }
    }


    @RequestMapping(value = "/user/resetpassword")
    @ResponseBody
    @WebLog(description = "重置密码操作")
    public String resetpassword(HttpServletRequest request) {
        Map map = new HashMap();

        String account = request.getParameter("account");
        String token = request.getParameter("token");
        User user = userService.getByAccount(account);
        if (user != null && user.getAccount().equals(account)) {
            //查询修改记录中是否存在
            Resetpwdlog resetpwdlog = resetpwdlogService.getById(account);
            if (resetpwdlog == null) {
                map.put(PubConstant.flag, PubConstant.failed + "_illagel");
                return JSONUtils.toJSONString(map);
            } else {
                if (resetpwdlog.getSubmitTime() == null || resetpwdlog.getToken() == null) {
                    map.put(PubConstant.flag, PubConstant.failed);
                    return JSONUtils.toJSONString(map);
                }
                int num = DateUtil.judgeMinutesTimeBetween(resetpwdlog.getSubmitTime(), DateUtil.getCurrentTime());
                if (num > PubConstant.MAIL_CODE_EFFECT_MINUTES) {
                    map.put(PubConstant.flag, PubConstant.failed + "_uneffect");
                    return JSONUtils.toJSONString(map);
                }
                if (!resetpwdlog.getToken().equals(token)) {
                    map.put(PubConstant.flag, PubConstant.failed + "_illagel");
                    return JSONUtils.toJSONString(map);
                }
            }
            //重置密码
            String password = request.getParameter("password");
            password = MD5.getMD5ofStr(password);
            user.setPassword(password);

            user.setUpdateTime(DateUtil.getCurrentTime());
            userService.saveOrUpdate(user);
            map.put(PubConstant.flag, PubConstant.success);
            return JSONUtils.toJSONString(map);
        } else {
            map.put(PubConstant.flag, PubConstant.failed + "_account");
            return JSONUtils.toJSONString(map);

        }
    }

    @RequestMapping(value = "/user/logout", method = RequestMethod.POST)
    @ResponseBody
    @WebLog(description = "登出系统")
    public String logout(HttpServletRequest request) {
        HttpSession session = request.getSession();
        session.invalidate();
        Map map = new HashMap();
        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }

    @RequestMapping(value = "/user/register")
    @ResponseBody
    @WebLog(description = "用户注册页面")
    public String uregister(HttpServletRequest request) {
        Map map = new HashMap();

        String verifyCode = (String) request.getSession().getAttribute("VerifyCode");
        String vercode = request.getParameter("vercode");
        if (verifyCode == null || vercode == null || !vercode.toUpperCase().equals(verifyCode.toUpperCase())) {
            map.put(PubConstant.flag, "vercode_error");
            request.getSession().removeAttribute("VerifyCode");
            return JSONUtils.toJSONString(map);
        }

        String account = request.getParameter("account");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        String email = request.getParameter("email");//使用邮箱注册

        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("account", account);

        User user = (User) userService.getObj(queryWrapper);
        if (user != null) {
            request.getSession().removeAttribute("VerifyCode");
            map.put(PubConstant.flag, PubConstant.exsit + "_account");
            return JSONUtils.toJSONString(map);
        }

        QueryWrapper<User> queryWrapper2 = new QueryWrapper();
        queryWrapper2.eq("nickname", nickname);

        User user2 = (User) userService.getObj(queryWrapper2);
        if (user2 != null) {
            request.getSession().removeAttribute("VerifyCode");
            map.put(PubConstant.flag, PubConstant.exsit + "_nickname");
            return JSONUtils.toJSONString(map);
        }
        String mailVerifyCode = (String) request.getSession().getAttribute("mailVerifyCode");
        String mailVerifyCodeTime = (String) request.getSession().getAttribute("mailVerifyCodeTime");

        String smscode = request.getParameter("smscode");

        if (smscode != null && mailVerifyCode != null && smscode.equals(mailVerifyCode)) {
            //邮箱验证码正确
            int num = DateUtil.judgeMinutesTimeBetween(mailVerifyCodeTime, DateUtil.getCurrentTime());
            if (num > PubConstant.MAIL_CODE_EFFECT_MINUTES) {
                //邮箱验证码超时
                map.put(PubConstant.flag, PubConstant.failed + "_smscode_timeout");
                return JSONUtils.toJSONString(map);
            }
        } else {
            //邮箱验证码错误
            map.put(PubConstant.flag, PubConstant.failed + "_smscode");
            return JSONUtils.toJSONString(map);
        }

        User domain = new User();
        domain.setAccount(account);
        domain.setNickname(nickname);
        domain.setEmail(email);
        domain.setPassword(MD5.getMD5ofStr(password));
        domain.setCreateTime(DateUtil.getCurrentTime());
        domain.setStatus(PubConstant.USER_STATUS_0);
        domain.setProphoto(PubConstant.DEF_USER_PHOTO_NAME);
        domain.setErrorCount(0);//初始化错误登录次数为0
        userService.save(domain);
        request.getSession().removeAttribute("VerifyCode");
        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }

    @GetMapping("/user/forget")
    @WebLog(description = "忘记密码页面")
    public String forget(HttpServletRequest request, Model model) {
        request.getSession().invalidate();
        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);

        return "forget";
    }

    @GetMapping("/userinfo/{id}")
    @WebLog(description = "用户信息")
    public String userinfo(@PathVariable int id, HttpServletRequest request, Model model) {
        //防止恶意查询 只有当前登录用户与要访问的用户为同一个人的时候才能显示
        User user = (User) request.getSession().getAttribute(PubConstant.GLOBAL_SESSION_NAME);
        if (user == null || user.getId() != id) {
            return "redirect:/error/403";
        }

        Myinfo myinfo = myinfoService.getById(PubConstant.MY_INFO_ID);
        model.addAttribute("myinfo", myinfo);

        // 分类信息
        List<Map> typesList = typeService.selectByShowFlag(PubConstant.YES_NO_Y, PubConstant.INDEX_TOP_TYPE_COUNT);
        model.addAttribute("types", typesList);

        // 标签信息
        List<Map> tagList = tagService.selectTags(PubConstant.INDEX_TOP_TAG_COUNT, PubConstant.YES_NO_Y);
        model.addAttribute("tags", tagList);

        User domain = new User();
        domain = userService.getById(id);
        domain.setPassword(null);//防止恶意获取用户密码信息
        model.addAttribute("user", domain);

        return "userinfo";
    }

    @PostMapping(value = "/user/update")
    @ResponseBody
    public String uupdate(HttpServletRequest request, User user) {
        Map map = new HashMap<Object, Object>();
        String email = user.getEmail();
        if (email != null && !"".equals(email)) {
            User domain = userService.getByEmail(email);
            if (domain != null && !domain.getAccount().equals(user.getAccount())) {
                map.put(PubConstant.flag, PubConstant.failed + "_email");
                return JSONUtils.toJSONString(map);
            }
        } else {
            map.put(PubConstant.flag, PubConstant.failed);
            return JSONUtils.toJSONString(map);
        }
        user.setUpdateTime(DateUtil.getCurrentTime());
        userService.saveOrUpdate(user);

        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }

    /**
     * 获取验证码
     *
     * @param request
     * @param response
     */
    @GetMapping("/verifyCode")
    @WebLog(description = "获取图片验证码")
    public void verifyCode(HttpServletRequest request, HttpServletResponse response) {
        IVerifyCodeGen iVerifyCodeGen = new VerifyCodeGenImpl();
        try {
            //设置长宽
            VerifyCode verifyCode = iVerifyCodeGen.generate(100, 28);
            String code = verifyCode.getCode();
            //将VerifyCode绑定session
            request.getSession().setAttribute("VerifyCode", code);
            //设置响应头
            response.setHeader("Pragma", "no-cache");
            //设置响应头
            response.setHeader("Cache-Control", "no-cache");
            //在代理服务器端防止缓冲
            response.setDateHeader("Expires", 0);
            //设置响应内容类型
            response.setContentType("image/jpeg");
            response.getOutputStream().write(verifyCode.getImgBytes());
            response.getOutputStream().flush();
        } catch (IOException e) {
        }
    }

    //// ==========================后台==============================///////
    // 列表页面
    @RequestMapping(value = "/manage/user/list", method = RequestMethod.GET)
    public String list() {
        return "page/user/list";
    }

    // 修改页面
    @RequestMapping(value = "/manage/user/update")
    public String update(HttpServletRequest request, Model model) {
        int id = Integer.parseInt(request.getParameter("id"));
        User user = userService.getById(id);
        model.addAttribute("user", user);
        return "page/user/update";
    }

    // 列表数据
    @RequestMapping(value = "/manage/user/data")
    @ResponseBody
    public String data(HttpServletRequest request) {
        Map map = new HashMap<Object, Object>();
        int pageSize = 5;// 默认每页显示5条记录
        int pageNum = 1;
        try {
            pageNum = Integer.parseInt(request.getParameter("page"));
            pageSize = Integer.parseInt(request.getParameter("limit"));
        } catch (Exception e) {
        }
        PageHelper.startPage(pageNum, pageSize);
        List<Map> userList = userService.list();

        PageInfo<Map> pageInfo = new PageInfo<Map>(userList);
        map.put("data", userList);
        map.put("code", 0);
        map.put("count", pageInfo.getTotal());
        return JSONUtils.toJSONString(map);
    }

    // 修改用户状态
    @RequestMapping(value = "/manage/user/status")
    @ResponseBody
    @Transactional
    public String show(HttpServletRequest request) {
        Map map = new HashMap<Object, Object>();
        String account = request.getParameter("account");
        User domain = userService.getByAccount(account);
        String status = request.getParameter("status");
        if (PubConstant.USER_STATUS_0.equals(status)) {
            domain.setErrorCount(0);
        }
        domain.setStatus(status);
        userService.saveOrUpdate(domain);
        /*String status = request.getParameter("status");
        userService.updateStatusByAccount(account, status);*/
        map.put(PubConstant.flag, PubConstant.success);
        return JSONUtils.toJSONString(map);
    }

}
